<template>
  <div id="map"></div>
  <div id="info">&nbsp;</div>
  <div class="webgl-clear-btn" @click="clearWebgl">清除webgl内存泄漏</div>
</template>

<script setup>
import "ol/ol.css";
import Map from "ol/Map";
import View from "ol/View";
import XYZ from "ol/source/XYZ";
import Feature from "ol/Feature";
import Layer from "ol/layer/Layer.js";
import TileLayer from "ol/layer/Tile";
import VectorSource from "ol/source/Vector";
import Point from "ol/geom/Point";
import LineString from "ol/geom/LineString";
import WebGLPointsLayer from "ol/layer/WebGLPoints.js";
import WebGLVectorLayerRenderer from "ol/renderer/webgl/VectorLayer.js";
import { fromLonLat } from "ol/proj.js";
import { onMounted } from "@vue/runtime-core";
import nansha_data from "./nansha_data";
import map_data from "./map_data";

let map;
let selected = null;
let highlight;
const style = {
  "stroke-color": ["*", ["get", "COLOR"], [220, 220, 220]],
  "stroke-width": 10,
  "stroke-offset": -1,
  "fill-color": ["*", ["get", "COLOR"], [255, 255, 255, 0.6]],
};
class WebGLLayer extends Layer {
  createRenderer() {
    return new WebGLVectorLayerRenderer(this, {
      style,
    });
  }
}
let featureOverlay;

// 创建地图容器
function initMap() {
  map = new Map({
    target: "map",
    // 天地图
    layers: [
      new TileLayer({
        source: new XYZ({
          url: "http://map.geoq.cn/ArcGIS/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}",
        }),
      }),
    ],
    // 南沙区中心点
    view: new View({
      center: fromLonLat([113.44, 22.73]),
      zoom: 10,
    }),
  });
}
// 绘制点要素
function addPoint() {
  const pointFeature = [];
  for (let i = 0; i <= nansha_data.junction_x.length - 1; i++) {
    pointFeature.push(
      new Feature({
        geometry: new Point(
          fromLonLat([nansha_data.junction_y[i], nansha_data.junction_x[i]])
        ),
        name: "Point",
      })
    );
  }
  const predefinedStyles = {
    icons: {
      "icon-src": "data/icon.png",
      "icon-width": 18,
      "icon-height": 28,
      "icon-color": "lightyellow",
      "icon-rotate-with-view": false,
      "icon-displacement": [0, 9],
    },
    triangles: {
      "shape-points": 3,
      "shape-radius": 9,
      "shape-fill-color": [
        "interpolate",
        ["linear"],
        ["get", "population"],
        20000,
        "#5aca5b",
        300000,
        "#ff6a19",
      ],
      "shape-rotate-with-view": true,
    },
    "triangles-latitude": {
      "shape-points": 3,
      "shape-radius": [
        "interpolate",
        ["linear"],
        ["get", "population"],
        40000,
        6,
        2000000,
        12,
      ],
      "shape-fill-color": [
        "interpolate",
        ["linear"],
        ["get", "latitude"],
        -60,
        "#ff14c3",
        -20,
        "#ff621d",
        20,
        "#ffed02",
        60,
        "#00ff67",
      ],
      "shape-opacity": 0.95,
    },
    circles: {
      "circle-radius": [
        "interpolate",
        ["linear"],
        ["get", "population"],
        40000,
        4,
        2000000,
        14,
      ],
      "circle-fill-color": ["match", ["get", "hover"], 1, "#ff3f3f", "#006688"],
      "circle-rotate-with-view": false,
      "circle-displacement": [0, 0],
      "circle-opacity": [
        "interpolate",
        ["linear"],
        ["get", "population"],
        40000,
        0.6,
        2000000,
        0.92,
      ],
    },
    "circles-zoom": {
      // by using an exponential interpolation with a base of 2 we can make it so that circles will have a fixed size
      // in world coordinates between zoom level 5 and 15
      "circle-radius": [
        "interpolate",
        ["exponential", 2],
        ["zoom"],
        5,
        1.5,
        15,
        1.5 * Math.pow(2, 10),
      ],
      "circle-fill-color": ["match", ["get", "hover"], 1, "#ff3f3f", "#006688"],
      "circle-displacement": [0, 0],
      "circle-opacity": 0.95,
    },
    "rotating-bars": {
      "shape-rotation": ["*", ["time"], 0.13],
      "shape-points": 4,
      "shape-radius": 4,
      "shape-radius2": 4 * Math.sqrt(2),
      "shape-scale": [
        "array",
        1,
        ["interpolate", ["linear"], ["get", "population"], 20000, 1, 300000, 7],
      ],
      "shape-fill-color": [
        "interpolate",
        ["linear"],
        ["get", "population"],
        20000,
        "#ffdc00",
        300000,
        "#ff5b19",
      ],
      "shape-displacement": [
        "array",
        0,
        [
          "interpolate",
          ["linear"],
          ["get", "population"],
          20000,
          2,
          300000,
          14,
        ],
      ],
    },
  };
  const newStyle = predefinedStyles["circles"];
  const pointsLayer = new WebGLPointsLayer({
    source: new VectorSource({
      features: pointFeature,
    }),
    style: newStyle,
  });
  map.addLayer(pointsLayer);
}
// 绘制线要素
function addLine() {
  const lineFeature = [];
  for (let i = 0; i <= nansha_data.pipe_vertices.length - 1; i++) {
    let res = [];
    nansha_data.pipe_vertices[i].forEach((item) => {
      res.push(fromLonLat([item[1], item[0]]));
    });
    lineFeature.push(
      new Feature({
        geometry: new LineString(res),
        name: "Line",
      })
    );
  }
  let style;
  const getStyle = (dash, pattern) => {
    let newStyle = {
      variables: style
        ? style.variables
        : {
            width: 10,
            offset: 0,
            capType: "butt",
            joinType: "miter",
            miterLimit: 10, // ratio
            dashLength1: 25,
            dashLength2: 15,
            dashLength3: 15,
            dashLength4: 15,
            dashOffset: 0,
            patternSpacing: 0,
          },
      "stroke-width": ["var", "width"],
      "stroke-color": "rgba(24,86,34,0.7)",
      "stroke-offset": ["var", "offset"],
      "stroke-miter-limit": ["var", "miterLimit"],
      "stroke-line-cap": ["var", "capType"],
      "stroke-line-join": ["var", "joinType"],
    };
    if (dash) {
      newStyle = {
        ...newStyle,
        "stroke-line-dash": [
          ["var", "dashLength1"],
          ["var", "dashLength2"],
          ["var", "dashLength3"],
          ["var", "dashLength4"],
        ],
        "stroke-line-dash-offset": ["var", "dashOffset"],
      };
    }
    if (pattern) {
      delete newStyle["stroke-color"];
      newStyle = {
        ...newStyle,
        "stroke-pattern-src": "data/dot.svg",
        "stroke-pattern-spacing": ["var", "patternSpacing"],
      };
    }
    return newStyle;
  };
  style = getStyle(false, false);
  class WebGLLayer extends Layer {
    createRenderer() {
      return new WebGLVectorLayerRenderer(this, {
        className: this.getClassName(),
        style,
      });
    }
  }
  const vectorLayer = new WebGLLayer({
    source: new VectorSource({
      features: lineFeature,
    }),
  });
  map.addLayer(vectorLayer);
}
function displayFeatureInfo(pixel) {
  const feature = map.forEachFeatureAtPixel(pixel, function (feature) {
    return feature;
  });

  const info = document.getElementById("info");
  if (feature) {
    info.innerHTML = feature.get("ECO_NAME") || "&nbsp;";
  } else {
    info.innerHTML = "&nbsp;";
  }

  if (feature !== highlight) {
    if (highlight) {
      featureOverlay.getSource().removeFeature(highlight);
    }
    if (feature) {
      featureOverlay.getSource().addFeature(feature);
    }
    highlight = feature;
  }
}
// 点击事件
function addHandler() {
  map.on("click", (ev) => {
    if (selected !== null) {
      selected.set("hover", 0);
      selected = null;
    }
    map.forEachFeatureAtPixel(ev.pixel, function (feature) {
      feature.set("hover", 1);
      selected = feature;
      return true;
    });
    const pixel = map.getEventPixel(ev.originalEvent);
    displayFeatureInfo(pixel);
  });
}
function clearWebgl() {
  let canvas = document.getElementsByTagName("canvas");
  console.log("canvas:", canvas);
  const gl = canvas[1].getContext("webgl");
  console.log("gl:", gl);
  const lose_context = gl.getExtension("WEBGL_lose_context");
  console.log("lose_context", lose_context);
  lose_context.loseContext();
}

onMounted(() => {
  initMap();
  featureOverlay = new WebGLLayer({
    source: new VectorSource(),
    map: map,
    style: {
      "stroke-color": "rgba(255, 255, 255, 0.7)",
      "stroke-width": 1,
    },
  });
  addHandler();
  addLine();
  // addPoint();
});
</script>

<style scoped>
#map {
  width: 100vw;
  height: 100vh;
}
.webgl-clear-btn {
  background: #fff;
  padding: 10px;
  border-radius: 5px;
  position: fixed;
  right: 10px;
  top: 10px;
  cursor: pointer;
}
</style>
